package com.hzhq.contract.service.impl;

import com.hzhq.contract.bean.dto.AttachmentDTO;
import com.hzhq.contract.bean.dto.ContractDTO;
import com.hzhq.contract.bean.entity.*;
import com.hzhq.contract.bean.vo.ContractVO;
import com.hzhq.contract.convert.AttachmentConvertBasic;
import com.hzhq.contract.convert.ContractConvertBasic;
import com.hzhq.contract.convert.ContractStatusConvertBasic;
import com.hzhq.contract.convert.DepartConvertBasic;
import com.hzhq.contract.repo.*;
import com.hzhq.contract.service.ContractService;
import com.hzhq.contract.status.DefaultValue;
import com.hzhq.contract.util.Page2ResultUtil;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: hzhq1255
 * @mail: hzhq1255@163.com
 * @date: 2021/4/14 20:42
 * @desc:
 */
@Slf4j
@Service
public class ContractServiceImpl implements ContractService {
    
    @Autowired
    ContractRepository contractRepo;
    
    @Autowired
    UserRepository userRepo;
    
    @Autowired
    UserRoleRepository userRoleRepo;
    
    @Autowired
    DepartRepository departRepo;
    
    @Autowired
    ContractTypeRepository contractTypeRepo;
    
    @Autowired
    AttachmentRepository attachmentRepo;
    
    @Autowired
    ContractStatusRepository statusRepo;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    MongoOperations mongoOps;
    
    
    
    @Override
    public ContractDTO getOneById(String id) {
        return contractRepo.findByContractIdAndDeleted(new ObjectId(id), DefaultValue.NOT_DELETED).map(ContractConvertBasic.INSTANCE::poToDto).orElse(null);
    }
    
    @Override
    public ContractDTO getOneByName(String name) {
        return contractRepo.findByContractNameAndDeleted(name, DefaultValue.NOT_DELETED).map(ContractConvertBasic.INSTANCE::poToDto).orElse(null);
    }
    
    @Override
    public Page<ContractDTO> getAllPage(Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        Page<Contract> contractPage = contractRepo.findAllByDeleted(DefaultValue.NOT_DELETED,pageable);
        Page<ContractDTO> contractDTOPage = contractPage.map(ContractConvertBasic.INSTANCE::poToDto);
        return contractDTOPage;
    }
    
    @Override
    public Page<ContractDTO> getAllPageByUserDepart(String username, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        Optional<User> userOptional = userRepo.findByUsernameAndDeleted(username,DefaultValue.NOT_DELETED);
//        List<Depart> departList = user.getRoleList().stream().filter(e-> e.getDeleted().equals(DefaultValue.NOT_DELETED) && e.getPassed().equals(DefaultValue.PASSED_REVIEW)).map(UserRole::getDepart).collect(Collectors.toList());
        List<Depart> departList = new ArrayList<>();
        return contractRepo.findAllByDepartInAndDeleted(departList,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByDepart(String departName, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        List<Depart> departList = new ArrayList<>();
        Depart depart = departRepo.findByDepartNameAndDeleted(departName,DefaultValue.NOT_DELETED).orElse(null);
        departList.add(depart);
        return contractRepo.findAllByDepartInAndDeleted(departList,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByType(String typeName, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        ContractType contractType = contractTypeRepo.findByTypeNameAndDeleted(typeName,DefaultValue.NOT_DELETED).orElse(null);
        return contractRepo.findAllByContractTypeAndDeleted(contractType,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByPassed(Integer passed, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        return contractRepo.findAllByPassedAndDeleted(passed,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByEdited(Integer edited, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        return contractRepo.findAllByEditedAndDeleted(edited,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByCreateUser(String createUser, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        Optional<User> userOptional = userRepo.findByUsernameAndDeleted(createUser,DefaultValue.NOT_DELETED);
        return contractRepo.findAllByCreateUserAndDeleted(userOptional.orElse(null),DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> getAllPageByApprovalPerson(String approvalPerson, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        Optional<User> userOptional = userRepo.findByUsernameAndDeleted(approvalPerson,DefaultValue.NOT_DELETED);
        return contractRepo.findAllByCreateUserAndDeleted(userOptional.orElse(null),DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }
    
    @Override
    public Page<ContractDTO> searchByName(String contractName,Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize, Sort.by(Sort.Direction.DESC,"contractId"));
        return contractRepo.findAllByContractNameLikeAndDeleted(contractName,DefaultValue.NOT_DELETED,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }

    @Override
    public Page<ContractDTO> getAllPage(ContractDTO contractDTO, Integer currentPage, Integer pageSize) {
        Pageable pageable = Page2ResultUtil.buildPageableByParam(currentPage, pageSize,
                Sort.by(Sort.Direction.DESC,"contractId"));
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("contractName", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("contactPerson",ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("templateName",ExampleMatcher.GenericPropertyMatchers.contains());

        Example<Contract> contractExample = Example.of(ContractConvertBasic.INSTANCE.dtoToPo(contractDTO),matcher);
        return contractRepo.findAll(contractExample,pageable).map(ContractConvertBasic.INSTANCE::poToDto);
    }

    @Override
    public ContractDTO save(ContractDTO contractDTO) {
//        attachmentRepo.saveAll(contractDTO.getAttachmentList().stream().map(AttachmentConvertBasic.INSTANCE::dtoToPo).collect(Collectors.toList()));
//        statusRepo.saveAll(contractDTO.getStatusList().stream().map(ContractStatusConvertBasic.INSTANCE::dtoToPo).collect(Collectors.toList()));
        Contract contract = contractRepo.save(ContractConvertBasic.INSTANCE.dtoToPo(contractDTO));
        return ContractConvertBasic.INSTANCE.poToDto(contract);
    }

    @Override
    public String deleteById(ObjectId id) {
        Optional<Contract> contractOptional = contractRepo.findByContractIdAndDeleted(id,DefaultValue.NOT_DELETED);
        if (contractOptional.isEmpty()){
            return null;
        }
        Contract contract = contractOptional.get();
        contract.setDeleted(DefaultValue.DELETED);
        Update update = new Update().set("deleted",DefaultValue.DELETED);
        mongoOps.updateMulti(Query.query(Criteria.where("contract_id").is(contract.getContractId())
                .and("deleted").is(DefaultValue.NOT_DELETED)),update,ContractStatus.class);
        mongoOps.updateMulti(Query.query(Criteria.where("_id").is(contract.getContractId())
                .and("deleted").is(DefaultValue.NOT_DELETED)),update,Attachment.class);
        return contractRepo.save(contract).getContractId().toString();
    }

    @Override
    public List<String> deleteByIds(List<ObjectId> ids) {
        List<Contract> deleteContracts = contractRepo.findAllByContractIdInAndDeleted(ids,DefaultValue.NOT_DELETED);
        List<String> deleteIds = new ArrayList<>();
        for (Contract contract:deleteContracts){
            String deleteId =  this.deleteById(contract.getContractId());
            if (deleteId != null){
                deleteIds.add(this.deleteById(contract.getContractId()));
            }
        }
        return deleteIds;
    }
}
